package org.NooLab.glue.filter;


   

import java.util.Arrays;

import org.NooLab.utilities.logging.PrintLog;
import org.NooLab.utilities.objects.StringedObjects;

import org.NooLab.glue.MessageBoard;
import org.NooLab.glue.components.*;
import org.NooLab.glue.interfaces.SynchronizedMessageDeliveryIntf;
import org.NooLab.glue.msgframe.*;
 
import org.NooLab.glue.net.RemoteAddress;
import org.NooLab.glue.recdispatcher.ReceptorLink;
import org.NooLab.glue.recdispatcher.ReceptorLinks;
import org.NooLab.glue.subscription.ActiveContextHeaderDescriptions;
import org.NooLab.glue.subscription.ContextHeaderDescription;
import org.NooLab.glue.subscription.FilterPackages;
import org.NooLab.glue.subscription.context.Context;
import org.NooLab.glue.subscription.context.ContextInfra;
import org.NooLab.glue.transaction.*;



/**
 * 
 * class for interpreting all messages, which arrived from a SOURCE participant
 * 
 * the counterpart for RECEPTORs is given by the class "MessageReceptor{}"
 * (and on the MessageBoard itself by "SourceMessageInterpreter{}")
 * 
 * this class runs in a separate thread for each message, entry point is the 
 * inner class "SourceMsgInterpretationProcess{}" in MessageBoard which is created
 * after message-based decoupling of processes in method "interpreteSourceMsg()" 
 * 
 * for this reason, we do not need separate threads here for the different tasks, except
 * for accelerated responses in case of multiple send outs... 
 * 
 */  
public class SourceMessageInterpreter 	extends 
													MessageInterpreter
										implements 
													SynchronizedMessageDeliveryIntf{
 
	SubscriptionHandlerInterpreter subscriptionHandler ;

	ReceptorLinks receptorLinks;
	
	SourceMessageInterpreter smi;
	
	CtxtXMessage cxmsg;
	
	public SourceMessageInterpreter( MessageBoard messageboard, 
									 FilterPackages filters, 
									 PrintLog outprn){
		super( messageboard, filters, outprn );
	
		subscriptionHandler = new SubscriptionHandlerInterpreter( messageboard, filters, outprn);
	
		smi = this;
		cxmsg = new CtxtXMessage(out);
	}  

	
	
	
	/**
	 * this is called from a FiFo thread, which creates a processing thread, it is a second-line dispatcher;
	 * 
	 * TODO: context handling, filters
	 * 
	 * @param xmlmsg
	 */
	public int interpretingSingleSourceMessage( Message msg){
		
		int result= -1;
		String rawXmlMsg, role  ;
		int p1;
		String[] rawIndicators ;
		XMessage xmsg ;
		 
		boolean isTransaction=false;
		
		
		receptorLinks = messageBoard.getReceptorLinks();
		receptorLinks.setCallback( this );
		
		
		rawXmlMsg = msg.rawXmlMsg ;
		
		// the classed thread ("SourceHandler") will take it in FiFo style and 
		// route it one by one to interpreteSourceMsg)=
		
		xmsg = new XMessage(out) ;
		
		
// if (rawXmlMsg.contains( "control")){
if (rawXmlMsg.contains( "cancel x")){
	p1=0;
	out.print(5,rawXmlMsg+"\n\r-------------------") ;
}

		//"<origin ... 
		originatorID = xmsg.getInfoFromProlog( rawXmlMsg, "origin", "id", ".");
		rawXmlMsg = xmsg.removePrologFromXml(rawXmlMsg) ;
		
		
		// now it will be taken acc. to FiFo by the "SourceHandler{}"
		role = xmsg.getSpecifiedInfo(rawXmlMsg, "//messageboard", "role").toLowerCase();

		 
		try{
			if (msgMonitor == null) {
				msgMonitor = mbf.getMsgBoardMonitor();
			}
			if (msgMonitor != null) {
				msgMonitor.addObservation(1, rawXmlMsg.length());
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		 
		
		if ((rawXmlMsg.length() > 40) && (role.contentEquals("source"))){
			// return a message to the sender of the message 
			
			rawIndicators = new String[]{"<request ","type=\"transaction\""} ;
			
			
			
			if (originatorID.length()==0){
				originatorID = xmsg.getSpecifiedInfo(rawXmlMsg, "//originator", "id") ;
			}
			
			// note, that in all methods we have to insert the  originatorID into the xml using "xmsg.insertRawToXml()"!!
			if (sourceVariant_RequestForTransactionReceipt( xmsg, rawXmlMsg ,rawIndicators) ){ return 0; }
			
			p1 = rawXmlMsg.indexOf("<transaction>");
			
			if (p1>0){
				// we are dealing with an ongoing transaction
				result= 0;
				
				isTransaction=true;
				rawIndicators = new String[]{"<request ","type=\"delivery\"","<data"} ;
				if (sourceVariant_DataAcceptAndRelayToReceptor( xmsg, rawXmlMsg ,rawIndicators) ){ 
					//result = false, if no matching client is found
					return result; 
				}else{
					rawIndicators = new String[]{"<request ","type=\"relay\"","<data","<relay>"} ;
					// note that the transaction id is NOT the original one, but the LOCAL one, related to the relay
					if (sourceVariant_RelayedDataRelayToReceptor( xmsg, rawXmlMsg ,rawIndicators) ){ 
						//result = false, if no matching client is found
						return result; 
					}else{  rawIndicators = new String[]{ "???", "<request ","type=\"delivery\"","<data"} ;
						if (sourceVariant_DelayedDataRelayToReceptor( xmsg, rawXmlMsg ,rawIndicators) ){ 
							return result;
						}
					}
				}
				
 				// this one is used only by RESTful or other asynchronous services (incl. ftp)
				rawIndicators = new String[]{ "<request ", "type=\"return\"", "content=", "transaction id=\"", "secret=", } ;
				if (sourceVariant_ResultsReturnDeliveryAsResource(xmsg, rawXmlMsg ,rawIndicators) ){ return result; }
				// 				
				
				rawIndicators = new String[]{"<confirmation ", "type=\"results\"", "<transaction id=\"", "state="} ;
				if (sourceVariant_ResultDeliveryConfirmation( xmsg, rawXmlMsg ,rawIndicators) ){ return result; }
				  
				rawIndicators = new String[]{"transactionID value=\"", "<notification", "request=\"stop"} ;
				if (sourceVariant_ResultsDeliveryDenied( xmsg, rawXmlMsg ,rawIndicators) ){ return result; }

				rawIndicators = new String[]{"transactionID value=\"", "<notification", "<action","<issuer"} ;
				if (sourceVariant_TransactionHandlingExplicites( xmsg, rawXmlMsg ,rawIndicators) ){ return result; }
				
				// re-ordered from top position
				rawIndicators = new String[]{"transactionID value=\"", "<notification", "request=\"get"} ;
				if (sourceVariant_ResultsReturnDelivery( xmsg, rawXmlMsg ,rawIndicators) ){ return result; }
				
				rawIndicators = new String[]{"<control ","type=\"cancel\"","param=\"", "<transaction ", "<instance "} ;
				if (sourceControl_CancelReceptorTaskbyTransactionID( xmsg, rawXmlMsg ,rawIndicators) ){ 
					return result;
				}

				
				result = -3;
			} // xml contains "<transaction>" ?
			 
			
			
			// sub-types : things like subscription, defining filters, mode of connection
			p1 = rawXmlMsg.indexOf("<linkage>"); 
			if (p1>0){
				result= 0;
				 
				
				result = -3;;
			} 
			
			p1 = rawXmlMsg.indexOf("<subscription") ;
			if ((p1>0) && (isTransaction==false)){
			
				// primary handling of subscriptions is the same for sources and receptors...
				
				// hence we route it..
				
				result = subscriptionHandler.go(rawXmlMsg) ;
				if (result==0){ return result;}
			}
			
			p1 = rawXmlMsg.indexOf("<control>"); 
			if (p1>0){
				result= 0;
				 
				
				result = -3;;
			} // a control task message from Source?
			
			// ? reserved
			p1 = rawXmlMsg.indexOf("<system>");
			if (p1>0){
				result= 0;
				 
			 
				result = -3;
			}
			
		} // message has content of sufficient length 
		return result ;
	}
	
	
	private boolean sourceVariant_ResultsReturnDelivery( XMessage xmsg, String rawXmlMsg, String[] rawIndicators ) {
		boolean result=false ;
		int p1 ,p2,r;
		long instanceID,transactionID,iid,tid;
		String role, bufferfilename, tfilename,secret,xmloutmsg,clisecret  ;
		Transaction transaction=null;
		
		XRegistration xreg ;
		
		@SuppressWarnings("unused")
		Object objFromFile, transObj;
		RemoteAddress address;
		
		result = xmsg.rawIndicatorsCheck( rawXmlMsg, rawIndicators);
	
		 
		if (result==false){
			// rawIndicators = new String[]{"transactionID value=\"", "<notification", "request=\"get"} ;
			// unhealthy overlap, adhoc cure: exclude confirmations
			p1 = rawXmlMsg.indexOf("type=\"results"); 
			p2 = rawXmlMsg.indexOf("<confirmation"); 
			result = (p1>0) && (p2<0);
		}
		// signature:   {"transactionID value=\"", "<notification", "request=\"get"} ;
	
												out.print(3, "preparing to return the result package after triggered poll...   ");
		if ( result ){
			// result = false;
			 
			// variant 4 : results are about to be delivered to the source 
		
			 
				/* 	<transactionID value="265"/>
					<instanceID value="1583"/>
					<notification request="get" type="results"/>
				*/
				// => should contain the currently active receiving port of target participant!!
											
				instanceID = xmsg.getinstanceID(rawXmlMsg, "instanceID");
				transactionID = xmsg.getTransactionID(rawXmlMsg) ;
				
				xreg = messageBoard.retrieveRegistrationObject(instanceID); 
				// which instance? receptor or source?
				
				/*
				if ( alreadyReceivedTransactionResults.contains(transactionID)){
					
					// notification to MessageBoard : we are ready, some state message ...
					return true;
				}
				*/
				int rport=0;
				int ix = receptorLinks.getActivatedPorts().indexOf( rport );
				
				
				// returns an address object
				address = xmsg.getRemoteAddress(rawXmlMsg,""); // does not work ?
				role = xmsg.getSpecifiedInfo(rawXmlMsg, "role", "value");
				
												out.print(3, "serving poll for delivery of results to instance "+instanceID+" related to transaction "+transactionID);
											
				// transactions could be interrupted physically, thus we should not refer to the xreg
				secret = xmsg.getSpecifiedInfo(rawXmlMsg, "notification", "secret");
				
				if (role.length()==0){ // some kind of emergency...
					xreg = messageBoard.retrieveRegistrationObject(instanceID); 
																	  
					if (xreg != null) {
						role = xreg.getRole();
					}
				}
				
				// search for the file, representing the results of this transaction
				// and load the results of this transaction
				
				tfilename = msgBoardStorage.createTransactionDataObjTmpFilename( transactionID,instanceID );
				transObj = msgBoardStorage.readTransactionDataObj(tfilename) ;
				
				// not the correct location
				// x  where are results saved to ??
				Transaction t = messageBoard.getTransactions().getTransactionByID(transactionID);
				
				if ((t.getTransactState()>=Transaction.TS_RESULTS_RETURNED) || 
					(t.getTransactState()==Transaction.TS_TASK_CANCELED) ||
					(t.getTransactState()==Transaction.TS_TASK_TIMEDOUT) ){
					
					
					return true;
				}
	
				// bufferfilename = msgBoardStorage.createTransactionBufferfileName( iid,  tid, "BOARD", "BOARD") ;
				bufferfilename = msgBoardStorage.createTransactionBufferfileName( instanceID,  transactionID, "BOARD", "BOARD") ;
				// like:  D:/dev/java/data/test/mb/transferBuffer/board/~rn-382-so.btmp
				if (fileutil.fileexists(bufferfilename)==false){
					out.printErr(3, "Error while serving results: storage problem, buffer file does not exist ! -> "+bufferfilename);
					out.printErr(3, "      parameters...  role: "+role+" , instanceID: "+instanceID+" ,  transactionID: "+transactionID );
					
					
					if (t!=null){
						  
						t.setTransactState( Transaction.TS_TASK_UNKNOWNFAIL);
						messageBoard.getWaitingNotifications().removeNotificationByTransactionID(transactionID) ;
					}
				}
				
				objFromFile = msgBoardStorage.readTransactionDataObj(bufferfilename);
				
				if (objFromFile!=null){
					
					try{
	
						transaction = (Transaction)objFromFile ;
						
					}catch(ClassCastException cex){
						String str = cex.getMessage();
						if ((str.length()>0) && (str.contains("java.lang.Integer"))){
							r = (Integer)objFromFile ;
							out.printErr(3, "Unexpected result from 'readTransactionDataObj()' (ClassCastException): "+r);
						}
					}catch(Exception e){
					}
					
					if (transaction!=null){
						iid = transaction.getInstanceID() ;
						tid = transaction.getTransactionID() ;
						clisecret = transaction.getClientSecret() ;
						
						if (clisecret.length()==0){
							clisecret = secret ; 
							transaction.setClientSecret(secret) ;
						}
						// is request matching the saved instance ??
						if ( (address.getPort()>0) && (transactionID == tid) && (instanceID==iid) ){ // && (secret.contentEquals(clisecret)
							// prepare delivery xml: - transaction ID serves as a delivery receipt
							// the transaction may thus also contain any kind of "secret" (from the perspective of the MB)
							// the transaction object contains an encoded result object
	
							xmloutmsg = xmsg.createReturnOfDataUponNotification(transaction, role, secret);
					
							// send it back to the requester
							// SenderWrap sender = new Sender(messageBoard);
							// sender.sendingMessage( xmloutmsg, address.getPort() );
							 
							r = wrappedSending( xmsg, null, xmloutmsg, "", "", address.getPort()) ;
								if (r<0){
									out.printErr(3, "sendingMessage() failed in sourceVariant_ResultsReturnDelivery(), code="+r);
								}
												out.printErr(3, "\nresults for transaction "+transactionID+" sent to port "+address.getPort()) ;
												out.print(4, xmloutmsg);
							
							result = true;
						}
					// is sending was successful (confirmed receipt)
					}// transaction != null?
				} // objFromFile!=null
				else{
					out.print(2, "Error while serving results: storage problem, objFromFile==null, buffer file : "+ bufferfilename);
				}
		}
		
		return result;
	}



	private boolean sourceVariant_ResultsReturnDeliveryAsResource( XMessage xmsg, String rawXmlMsg, String[] rawIndicators ) {
		boolean result=false ;
		
		int sv = -1,r,ec=-1;
		long instanceID,transactionID,iid,tid;
		String secret, str,tfilename, bufferfilename, xmloutmsg="",role, errstr ="";
		
		
		
		boolean hb = false, is_NOT_old=false, is_very_old ;
		boolean saveOnTimeSet;
		
		Transaction transaction=null;
		XRegistration xreg ;
		@SuppressWarnings("unused")
		Object objFromFile, transObj;									
		
		
		result = xmsg.rawIndicatorsCheck( rawXmlMsg, rawIndicators);
		
		if ( result ){
			result = true;
												out.print(5,">>> request for results recognized -> sourceVariant_ResultsReturnDeliveryAsResource() <<<") ;
												out.print(6,"    "+rawXmlMsg);
												
			transactionID = xmsg.getTransactionID(rawXmlMsg) ;
			instanceID = xmsg.getinstanceID(rawXmlMsg, "instanceID");
			
			secret = xmsg.getSpecifiedInfo(rawXmlMsg, "request", "secret");
			
			role = xmsg.getSpecifiedInfo(rawXmlMsg, "role", "value");
			
			xreg = XRegistration.getItemByID( instanceID, messageBoard.getRegisteredInstances());
			
			BasicMessageParams basics = new BasicMessageParams();
			 
			basics.transactionID = transactionID;
			basics.instanceID = instanceID;
			basics.privateTransactionIdentifier = secret;
			basics.roleOfSender = role ;
			
			
			// we return the results only if the exist... state of transaction should match !
			transaction = transactions.getTransactionByID( transactionID );
			if (transaction!=null){
				
				saveOnTimeSet = transaction.getTimeofDelivery()<1000;

				// what's about the age ? if the transaction has its own expiry, this will be checked 
				is_NOT_old = transaction.isOld( _old_value,"min")==false ; // depends also on timeofdelivery: <- which can be adjusted through keepalive message for a particular transaction

				if (saveOnTimeSet){
					messageBoard.getTransactions().save();
				}
				
				sv = transaction.getTransactState() ;
				ec = transaction.getTransactErrorState() ; 
				
				if ((sv >= Transaction.TS_TASK_CANCELED) && (sv <= Transaction.TS_TASK_UNKNOWN)){
					transaction.setTransactState( sv );
					sendErrorMessageToClient( xmsg, xreg,basics, Transaction.TS_TASK_CANCELED, "transfer failed", Transaction.TS_ERR_UNKNOWN ) ;
					return true;
				}
				if (sv==Transaction.TS_RESULTS_BUFFERED){
					//
				}
				
				if ( (sv>Transaction.TS_TASK_UNKNOWN) && (sv<Transaction.TS_TASK_CANCELED) ){
					sendErrorMessageToClient( xmsg, xreg,basics, Transaction.TS_TASK_CANCELED , "", Transaction.TS_ERR_STOPPED ) ;
					return true;
				}
				
				// we also test buffered results for their age! 
				// the test for existing buffer is later...
				if (sv == Transaction.TS_RESULTS_BUFFERED){
					
					if (is_NOT_old == false){
						sendErrorMessageToClient( xmsg, xreg,basics, Transaction.TS_RESULTS_BUFFERED , "", Transaction.TS_ERR_TIMEDOUT ) ;
						// the client then may decide whether it want to issue a special request
						// ( not implemented yet )
						return true;
					}
				}
				
				if ((sv < Transaction.TS_RESULTS_BUFFERED) && (sv >= Transaction.TS_TASK_ACCEPTED)   ){ // excludes also TS_TASK_TIMEDOUT
					
					if (is_NOT_old){
						int age_of_t = (int)(transaction.getAge(1)/1000/60) ; 
						out.print(4, "premature request for result on transaction (tid:"+transactionID+", age:"+age_of_t+" min) through polling in http contexts, state: "+sv+"...");
						/* 	the state might be 10 = accepted, ready for delivery to receptor, but
						 	it still may fail to be delivered to the receptor
							if it fails, we have to set the state accordingly over there
							but here this "prematurity" is not a problematic event...
							
							yet, in case of http we have to return a response, because otherwise the client does not know whether
							the line is down or no result is available, hence the client will wait until the connection has been timed out...
						*/ 
						if (messageBoard.getProtocolID() < MessageBoardFactoryProperties.protocolFTP ){
							sendErrorMessageToClient( xmsg, xreg,basics, Transaction.TS_TASK_DIGESTING, "", 0 ) ;
						}
						return true;
					}else{
						// error message
						if ((sv>=Transaction.TS_TASK_CANCELED)  ){
							if (sv<=Transaction.TS_TASK_UNKNOWN){
								// identified standard error
								sendErrorMessageToClient( xmsg, xreg,basics, Transaction.TS_TASK_CANCELED, "", Transaction.TS_ERR_TIMEDOUT ) ;
								
							}else{
								// either RUN or RETURNS ...
								is_very_old = transaction.isOld( _veryold_value,"day")  ;
								if (is_very_old){
									out.print(4, "transaction (tid:"+transactionID+" is very old and will be cancelled.");
									transaction.setTransactState(Transaction.TS_TASK_TIMEDOUT);
									sendErrorMessageToClient( xmsg, xreg,basics, Transaction.TS_TASK_TIMEDOUT , "", Transaction.TS_ERR_TIMEDOUT ) ;
								}
							}
						}else{
							is_very_old = transaction.isOld(_veryold_value,"day")  ;
							
							// >accepted < canceled ?
							if (sv > Transaction.TS_TASK_ACCEPTED){
								
								if (is_very_old){
									out.print(4, "transaction (tid:"+transactionID+" is very old and will be cancelled.");
									transaction.setTransactState(Transaction.TS_TASK_TIMEDOUT);
									sendErrorMessageToClient( xmsg, xreg,basics, Transaction.TS_TASK_TIMEDOUT , "", Transaction.TS_ERR_TIMEDOUT  ) ;
								}
							}
							if (sv == Transaction.TS_TASK_ACCEPTED){
								if (is_very_old){
									out.print(4, "transaction (tid:"+transactionID+" is very old and will be cancelled.");
									transaction.setTransactState(Transaction.TS_TASK_TIMEDOUT); 
									sendErrorMessageToClient( xmsg, xreg,basics, Transaction.TS_TASK_TIMEDOUT, "never been transferred to receptor, now timed out.", Transaction.TS_ERR_TIMEDOUT  ) ;
								} else{
									out.print(4, "transaction (tid:"+transactionID+" is rather old, a notification has been sent.");
									// already old... we leave it to the SOURCE what to do then... it may cancel the task with a special request
									sendErrorMessageToClient( xmsg, xreg,basics, Transaction.TS_TASK_DELAYED, "not yet transferred to receptor",Transaction.TS_ERR_NO ) ;
								}
								
							}
						}
						
					}
				}else{
					// either archived or closed, or not started, or not perfectly accepted
					if (sv!=Transaction.TS_RESULTS_BUFFERED){
						transaction.setTransactState(Transaction.TS_TASK_UNKNOWN);
						sendErrorMessageToClient( xmsg, xreg,basics, Transaction.TS_CLOSED , "", Transaction.TS_ERR_TRANSINVALID ) ;
					}else{
						 
					}
					 
				}
			}else{ // transaction = null, e.g. the board did not load it after restart...
				
				// we did not find the transaction, it is not available any more
				// return a message to the requesting client,
				errstr = "Transaction unknown";
				
				if (xreg!=null){
												out.print(2,"returning error message to client (id:"+xreg.getInstanceID()+") "+
														    "about invalid transaction (requested id:"+transactionID+" was not available), sending to port "+xreg.getClientListeningPort() ) ;
				    sendErrorMessageToClient( xmsg, xreg,basics, Transaction.TS_TASK_UNKNOWN, errstr,Transaction.TS_ERR_TRANSINVALID );
				} else{
					// we HAVE to return a message even in this case, otherwise the client will wait 18 seconds !!!
					// we can't use "sendErrorMessageToClient(()", since there the xreg is needed, so we use a simple send here
					//  creating a general unknown message
					// xmsg.create...
					SenderWrap sender = new SenderWrap(comBox);
					// but since xreg can not be found, we can serve this only if we are in http mode...
					// were we do not need a port..
					sender.sendingMessage( "", -1);
					sender=null;
				}
				return true;
			}
			
			// only if we COULD expect a file, we SHOULD expect a file...
			
			tfilename = msgBoardStorage.createTransactionDataObjTmpFilename( transactionID,instanceID );
			transObj = msgBoardStorage.readTransactionDataObj(tfilename) ;
			
			
			bufferfilename = msgBoardStorage.createTransactionBufferfileName( instanceID,  transactionID, "BOARD", "BOARD") ;
			hb = fileutil.fileexists(bufferfilename) ;
			
			// D:/dev/java/data/test/mb/transferBuffer/board/~rn-702-bo.btmp
			// yet there should also be a file
			// // D:/dev/java/data/test/mb/transferBuffer/board/~rn-702-so.btmp ....
			
			
			
			// there is nothing wrong, if the receptor is still working on it...
			// so, if it is not timed-out, and status is delivered, return a friendly status message
			// especially if there is not error at all...
			transaction = transactions.getTransactionByID( transactionID );
			
			if (transaction==null){
				// we leave this uncommented, it may be a fantasy request, or it may be too early after delivery...
				out.print(3,"transaction checked : "+transactionID+"  transaction not found, returning");
				// return true;
				ec = -5;
			}else{
			
				sv = transaction.getTransactState();
				ec = transaction.getTransactErrorState() ;
			}

			// a last check for the state of the transaction...
			if ( (ec==0) && (sv>0) && 
				 (sv!= Transaction.TS_TASK_CANCELED) && (sv != Transaction.TS_TASK_TIMEDOUT) &&	
				 (sv< Transaction.TS_CLOSED) && (sv != Transaction.TS_TASK_DENIED) &&
				 (sv> Transaction.TS_TASK_STARTDELIVERY) && (sv < Transaction.TS_RESULTS_BUFFERED) ){
				// for these state conditions, there is no bufferfile, yet everything is OK
				r = returnErrorMessageUponRequest( xmsg, xreg, basics, sv ,0, "") ;
				
				return true;
			}
			if ( (ec==0) && (sv == Transaction.TS_RESULTS_BUFFERED)){
				if (fileutil.fileexists( bufferfilename)==false){
					r = returnErrorMessageUponRequest( xmsg, xreg, basics, 26 , Transaction.TS_ERR_BUFFNOTFOUND, "") ;
					// we assume, that we already have sent it
					transaction.setState( Transaction.TS_CLOSED );
				}
			}
			
			/*
			   	TS_TASK_STARTDELIVERY = 12;
				TS_TASK_RELAYING    = 13;
				TS_TASK_DELIVERING  = 14;
				TS_TASK_DELIVERED   = 15;
	 			TS_TASK_DIGESTING   = 16;
	 			TS_TASK_CANCELED    = 17;
	 			TS_TASK_TIMEDOUT    = 18;
	 			TS_RECEPTOR_RUN     = 20;
	 			TS_RECEPTOR_RETURNS = 25;
	 			TS_RESULTS_BUFFERED = 26;
	 			TS_RESULTS_RETURNED = 28;
			*/
			 
			
			if (((transaction==null) || (hb==false) ) && (ec<0)){
				
				if (hb==false){
					ec = Transaction.TS_ERR_BUFFNOTFOUND;
					errstr = "Persistence storage file for requested transaction id="+transactionID+" not found for instance of id="+instanceID ;
				} else{
					errstr = "Requested transaction id="+transactionID+" unknown for instance of id="+instanceID ;
					ec = Transaction.TS_ERR_TRANSINVALID;
				}
												out.printErr(2,"sourceVariant_ResultsReturnDeliveryAsResource, errcode: "
																+ec+"  , "+ errstr);
				//  send message
				r = returnErrorMessageUponRequest( xmsg, xreg, basics, // transactionID, instanceID, role,secret, 
												   ec ,Transaction.TS_ERR_UNKNOWN, errstr) ;
				basics = null ;
				return true;
			}
			
			// delivery Is Not Possible yet, e.g. sv=10, ec=0 , task is at MessageBoard, but not yet calculated
			// thus empty return
			
			int deliveryReason = deliveryIsNotPossible( xmsg, xreg, basics, transaction, bufferfilename );
			if ((sv>Transaction.TS_TASK_ACCEPTED) && ( deliveryReason > 0)){
				
				out.printErr(2,"result delivery for transaction id="+transaction.getTransactionID()+" (iid:"+instanceID+") not possible (yet/anymore), reason:"+deliveryReason+" ...");
				return true;
			}else{
				// file found , is it an error at all?
				sv = transaction.getTransactState() ;
				
				if (sv== Transaction.TS_TASK_DIGESTING){
					errstr = "";
					
				}
				if (sv== Transaction.TS_TASK_DELIVERING){
					errstr = "";
				}
			}
			if (deliveryReason<0){
				// return true;
			}
												
			objFromFile = msgBoardStorage.readTransactionDataObj(bufferfilename);
			r = -3;
			
			if ((objFromFile!=null) ){ // && ( (Integer)objFromFile!=-1 )
											
				try{
	
					transaction = (Transaction)objFromFile ;
												out.print(3,"   ... does indeed exist ...");
					str = transaction.getClientSecret() ;
					iid = transaction.getTransactionID() ;
					
					r=0;
				}catch(ClassCastException cex){
					str = cex.getMessage();
					if ((str.length()>0) && (str.contains("java.lang.Integer"))){
						r = (Integer)objFromFile ;
						out.printErr(4, "Unexpected result from 'readTransactionDataObj()' (ClassCastException): not an transaction "+r+"\n"+
										"nothing will be returned from MessageBoard!");
						
						sendErrorMessageToClient( xmsg, xreg,basics, //transactionID,instanceID, role,  secret , 
													Transaction.TS_TASK_CANCELED,errstr, Transaction.TS_ERR_BUFFINVALID ) ;
						//  
						transactions.removeItem(transaction) ;
						msgBoardStorage.removeBufferFile(bufferfilename) ; // ????
						return true;
					}
				}catch(Exception e){
					r = -1;
				}

				
				if ((r==0) && (transaction!=null)){
				
					iid = transaction.getInstanceID() ;
					tid = transaction.getTransactionID() ;

					// so far we have excluded any possibility for an error state,
					// now, as the last step, we test whether the transaction need to be aligned and, if yes, 
					// whether it is aligned
					// if no alignment is expected, true will be returned
					
					boolean tiab = messageBoard.transactionIsAligned( iid,  tid);

					if (tiab){
						
						// 
						bufferfilename = msgBoardStorage.createTransactionBufferfileName( iid,  tid, "BOARD", "BOARD") ;
						hb = fileutil.fileexists(bufferfilename) ;
						if (hb){
							msgBoardStorage.removeBufferFile(bufferfilename);
						}
								
						// now creating response, which will return the transaction WITHIN SESSION
						xmloutmsg = xmsg.createReturnOfDataUponNotification( transaction, role, secret);
	
						// nothing will be added if the originatorID == "" in case of non-http-rest !!
						// xmloutmsg = xmsg.insertRawToXml( originatorID, "originator","id", xmloutmsg, "</messageboard>",1);
					
						r = wrappedSending( xmsg, xreg, xmloutmsg, "", "",0) ;
							if (r==0){
								xreg.removeTransactionToAlignment( tid );
								// removeTaskToAlignment(instanceID,  transID);
								
							}
					
						// see also "sourceVariant_ResultDeliveryConfirmation()", which handles the confirmation by the SOURCE
					
					}else{
						r = returnErrorMessageUponRequest( xmsg, xreg, basics, Transaction.TS_TASK_DELAYED,0, "please wait") ;
					}
					// we remove the buffer file, remove transaction from storage, ONLY upon the 
					// confirmation, that the results indeed arrived at the SOURCE
				 
				}
			}
			
		}
		return result;
	}


	/**
	 * 
	 * after requesting a transaction ID, we use the return tid for creating a data delivery message, then sending it
	 * 
	 * @param xmsg
	 * @param rawXmlMsg
	 * @param rawIndicators
	 * @return
	 */
	private boolean sourceVariant_DataAcceptAndRelayToReceptor( XMessage xmsg, String rawXmlMsg, String[] rawIndicators ){
		
		boolean result=false ;
		String xmloutmsg,str, filename, contentType="", task="", secret ="";
		int deliveryPort,r,n, relayByContext=0 ;
		boolean hb;
		long iid=0, xtiid=0,tid=0;
		
		BasicMessageParams basics;
		XRegistration xreg=null, xtreg =null;
		Object dataObj=null;
		Transaction transaction;
		AssimilateContext ac=null ;
		
		
		result = xmsg.rawIndicatorsCheck( rawXmlMsg, rawIndicators);
		
		// data are about to be delivered
		if ( result ){
			result = false;
		
				basics = new BasicMessageParams() ;


									if (rawXmlMsg.contains("<context")){
										out.print(4, "context-tag found in raw xml...");
									}else{
										out.print(3, "context-tag NOT found in raw xml!");
									}
			
			    transaction = null;
											out.print(3, "MB: message is a data delivery by SOURCE... ");
				int z=0;
				while ((transaction==null) &&(z<500)){
											delay(10);
				    transaction = xmsg.readTransactionDataDelivery( transactions , rawXmlMsg ) ;
				    z++;
				}
				
				if (transaction!=null){
											out.print(3, "delivered package has transaction id "+transaction.getTransactionID());
											
				    transaction.setState( Transaction.TS_DATA_ACCEPTING ) ;
				}else{
					                        out.printErr(3, "transaction unexpectedly == null!");
					return true ;
				}
				
				transaction.setTimeofDelivery( System.currentTimeMillis() );
				
				 
				if (transaction.getTransactState()< Transaction.TS_TASK_DELIVERED){
					transaction.incTaskRelayTrialCounter();
				}
				
				relayByContext = (int) xmsg.getSpecifiedValue( rawXmlMsg, "//transaction/taskrelay", "contextrequired");
				transaction.setRelayByContext( relayByContext );
				
				
				if (transaction.getTaskRelayTrialCounter() > transaction.getMaxRelayTrialCount()){  
					
					transaction.setTransactState( Transaction.TS_TASK_TIMEDOUT ) ;
					transactions.save();
					return true;
				}
				
				transactions.save();
				
				
				hb = mbf.getMessageBoard().checkTaskStackLimit();
				
				iid = transaction.getInstanceID() ;
				tid = transaction.getTransactionID() ;

				if (hb==false){
					
					transaction.setTransactState(Transaction.TS_TASK_CANCELED );
					transaction.setTransactErrorState( Transaction.TS_ERR_SRV_CAPACITY) ;
												out.print(2, "opening transaction cancelled, reason: TS_ERR_SRV_CAPACITY violated.");

					denyTaskAcceptance( xmsg, rawXmlMsg ,iid , tid, Transaction.TS_ERR_SRV_CAPACITY);
					
					transaction= null;
					mbf.getTransactions().removeItemByID(tid) ;
					
					return true;
				}

				
				basics.instanceID = iid;
				basics.transactionID = tid;
				basics.roleOfSender = xmsg.getSpecifiedInfo(rawXmlMsg, "messageboard", "role");
				
				secret = xmsg.getSpecifiedInfo(rawXmlMsg, "//transaction/request", "secret");
				
				basics.privateTransactionIdentifier = secret ;
				
				// contentType = transaction.getContentType();
				contentType = xmsg.getSpecifiedInfo(rawXmlMsg, "//transaction/content", "type");
				
												out.print(3,"sourceVariant_DataAcceptAndRelayToReceptor(), content type in transaction <"+tid+"> : "+contentType) ;
				 
				
				dataObj = xmsg.readTransactionDataDelivery( rawXmlMsg ) ;
				// this dataObj is the object-form of the String, which encodes the taskpackage
				
				// saving to tmp file, storing the filename to the transaction object, 
				// filepath e.g. D:/dev/java/data/test/mb/transactData/~tdata_tid-252_inid-1553.obj
				
				// problem : wrong path should not be below "/mb/config/..." but instead on "/mb/..." 
				filename = msgBoardStorage.createTransactionDataObjTmpFilename( transaction.getTransactionID(), transaction.getInstanceID() );
				
				r = msgBoardStorage.storeTransactionDataObj( dataObj, filename) ; // filename e.g. ~tdata_tid-252_inid-1553.obj
					// checks also if file exists after writing attempt...
				    if (r<0){
				    	out.printErr(1, "transaction (tid:"+tid+") could not be buffered, hence it will be lost.");
				    }
				
				if (transaction!=null){
					transaction.setState( Transaction.TS_TASK_ACCEPTED ) ;
				}
				
				// we also save the raw xml request as delivered by the SOURCE 
				filename = filename.replace("/~tdata_", "/~srcreq_") ;
				msgBoardStorage.storeTransactionDataObj( (Object)rawXmlMsg, filename) ;
				
				xmloutmsg = xmsg.prepareDataDeliveryMessage( rawXmlMsg , transaction, task ) ;
				
				// and the XML relayed to the RECEPTOR : => this will be taken in any kind of delay, or in case of httpc transport 
				filename = msgBoardStorage.createTransactionDataObjTmpFilename( transaction.getTransactionID(), 0 );
				filename = filename.replace("/~tdata_", "/~reqray_") ;
				msgBoardStorage.storeTransactionDataObj( (Object)xmloutmsg, filename) ;
				
				// => we will delete those files (1) when we get the results (2) after expiry/some days -> we store a notification for the SOURCE  
				 
				iid = transaction.getInstanceID() ;
				tid = transaction.getTransactionID() ;
				
				xreg = XRegistration.getItemByID(iid, registeredInstances);
				
				if (xreg.getAlignedResultsBasketSize()>=1){
					// in this case == at least semi-ordered... we need a tracking array for this registered SOURCE
					
					// the values will be within XREG!! 
					// yet, the MessageBoard needs to know which iids have to be supervised
					messageBoard.putTaskToAlignment( xreg, tid);
					
				}
				
			
				
				// if we are in HTTP-REST mode, then we never will relay the data directly, hence
				// we also do not try to find a matching client here either; 
				// instead, we simply have to store it, and to wait.
				
				if (messageBoard.getProtocolID() <= MessageBoardFactoryProperties.protocolFTP )
				{
					
												out.print(2,"Data task (delivered by instance id="+transaction.getInstanceID()+
															") of transaction id="+transaction.getTransactionID()+" buffered, now waiting for next receptor...");
					
					
					if (fileutil.fileexists(filename)){
						sendDataAcceptConfirmation( xmsg, transaction,0);
					
					}
					if (messageBoard.getProtocolID() <= MessageBoardFactoryProperties.protocolFTP ){
						return true;
					}
				}

				
				if (fileutil.fileexists(filename)){
					// this should use a separate sending thread...
					// otherwise we will loose 2+ seconds !
					sendDataAcceptConfirmation( xmsg, transaction,0);
				
				}
												out.print(2,"Data task (delivered by instance id="+transaction.getInstanceID()+
															") of transaction id="+transaction.getTransactionID()+" buffered, confirmation returned, now relaying to RECEPTOR...") ;
				
				// creating xml, routing the data to a OR the matching receptor
				
				deliveryPort = -3;
				
				 
				if (transaction.getContentType().trim().length()==0){
					transaction.setContentType( contentType );
				}
				// datatype = transaction.getType();
				contentType = transaction.getContentType();
				// note, that participants == xregs need to be tested -> instanceTested

											if (rawXmlMsg.contains("<context")){
												out.print(4, "context-tag found in raw xml...");
											}else{
												out.print(3, "context-tag NOT found in raw xml!");
											}
				if (rawXmlMsg.contains("<context")){ // does it contain a descriptive context info section
					// extract context and add it to the collection
					// will be done in a separate process
					int waitFor = 1;
					if (relayByContext <=0){
						waitFor = 0 ; 
						// not waiting if we have a normal transfer without subscription (respectively, waiting below),
						// else, if we have to check the subscription, we have to wait here for inserting our info
						// which we will check for just few step below
					}
					ac = (new AssimilateContext( rawXmlMsg, transaction)).get(waitFor); // indicates 
					// will quickly return from there... so we have a fork here
					// just to be sure not to miss the "true"-condition
					if (waitFor>=1){
						z=0;
						while ((z<40000) && (ac.finished==false)){
							delay(1); z++ ;
						}
					}
					// "relayByContext" indicates that msg should be transferred ONLY if the context info matches too 
					if ((relayByContext>0) && (ac.finished)){
						
						n = messageBoard.getActiveContextHeaderDescriptions().size() ;
									 
											out.print(2, "\nnow there are "+n+" items if the list of descriptive context info headers...") ;
											out.print(2, "going to check for a matching subscription (n="+n+", tid:"+transaction.getTransactionID()+" , iid:"+transaction.getInstanceID()+")...");
						 
						// this ALSO will immediately relay the message AS SUBSCRIPTION (NOT: a "task") to subscribers !
				        // if not (), but instead with parameters, then one of the subscribers is de-selected and 
						// instead returned to here by means of its iid... 
						
						// we check the info of THIS transaction ! 					
											xtiid = messageBoard.getMsgmatcherProcess().performMatchingRaid( transaction, "SOURCE",contentType);
						
						// now we can send the messages to the receptor !
						
						if (xtiid<=0){
											out.print(2, "No matching subscription found for transaction (tid:"+tid+").");
							return true;
						} else {
							// get port from iid
							xtreg = XRegistration.getItemByID( xtiid, registeredInstances);			
							deliveryPort = xtreg.getClientListeningPort() ;
						}
					}
					
					out.print(2, "assimilating context info into descriptive context info headers has been started, meanwhile continuing...") ;	
				}
				
				
				// "relayByContext" indicates that msg should be transferred ONLY if context info matches 
				// one of the subscriptions/futures;
				// after extraction, a check is triggered, ...if this check identifies
				// thus we do NOT send here directly
				if (relayByContext<=0){
					// note that the receptor can itself define whether it accepts msg just based on doc-type-match,
					//      or whether a context message should be present, and if yes, also should match
					
					// this is critical, could cause parallel delivery to a single receptor...
					// returns the port of a matching receptor
				    deliveryPort = clientMatcher.findMatchingParticipant( transaction, 0 ) ; 
				
										if (deliveryPort<0){
											// we should not drop an error, the transaction may time out
											out.print(3, "No matching RECEPTOR found for data type '"+contentType+"' of transaction ID "+ transaction.getTransactionID() +
														 ", transaction might be delayed or even time out.") ;
											// transaction.setState( Transaction.TS_TASK_DELAYED) ;
											transaction.setTransactErrorState( 0 ) ;
											transaction.setDeliveryPort(deliveryPort) ;
											 
											sendErrorMessageToClient( xmsg, xreg,basics, Transaction.TS_TASK_DELAYED, "results could be delayed.", 0) ;
											return true;
										} 
				}else{
					// subscribers are matched above (tcp) or upon request (http)
				}
				
		        // deliveryPort = -1 for http transport!
				// anyway, we perform the protocol test as well
			    result = true;	
	 		    
				if ( mbf.getFactoryProperties().getProtocolId() >= MessageBoardFactoryProperties.protocolTCP){
					
					if ((deliveryPort < 0) ) { // || (receptorLinks.getActivatedPorts().indexOf(deliveryPort)>=0)
						z=0;
						if (ac != null) {
							while ((ac.finished == false) && (z < 50)) {
								delay(2);
							}
						}
						return true;
					}
					 
											out.print(3, "relaying data to receptor using port "+deliveryPort+" for delivery ") ;
					// create the data delivery xml for the receptor
					// should indicate whether a result is expected
					// also datatype, contentType, partnerID, transactionID, data section
					// => we use the incoming xml and add/change some entries 
											if (xtreg!=null){
												iid = xtreg.getInstanceID() ;
												r = xtreg.getClientListeningPort() ;
											}
					 
					xmloutmsg = xmsg.prepareDataDeliveryMessage( rawXmlMsg , transaction, task ) ;
					 
					// in case of direct transport (=here) we have to be very careful with the assignment process;
					// since delivery of tasks can be faster than dispatching it, two+ processes maybe sent to the same instance
					// thus we need a class which implements a FiFo for tid <-> ports in a synchronized manner;
					// up to here, we are in parallel mode, yet, for the assignment of task and process we need  
					// a proper scheduling: no double assignments, and evenly distributed in case of many available processes;
					// the problem does not appear for http transport, because this completely relies on notifications and
					// client-centric initiation (NO push there at all)
			 	
											out.print(4, "... port "+deliveryPort+" will be mapped to transaction...");
											out.print(2, "inserting transaction to the device 'receptorLinks' for sending... ");
					
					transaction.setDeliveryPort(deliveryPort) ;
					transaction.setState( Transaction.TS_TASK_DELIVERING) ;
					
					str = rawXmlMsg;
					
					receptorLinks.put( transaction, xmloutmsg, deliveryPort) ; 
					// switch off for testing
					// r = wrappedSending( xmsg, null, xmloutmsg, "","", deliveryPort) ;
											
					
					transactions.save();
					str=str+" ";
					// this one moves to a method somewhere here, as it will be called back from rl
					
					// if it can not be confirmed, we have to unregister the intended RECEPTOR ! 
					 
					result = true;
				}
		  
		} // rawIndicators present ?
		
		return result;
	}
	
	
	private boolean sourceVariant_RequestForTransactionReceipt( XMessage xmsg, String rawXmlMsg, String[] rawIndicators){
		boolean result=false;
		
		int  r;
		
		long instanceID, transactionID;
		String xmloutmsg, clientsecret;
	
		Transaction transaction = null;
		XRegistration xreg;
		
		
		
		result = xmsg.rawIndicatorsCheck( rawXmlMsg, rawIndicators);
		// variant 1
		if ( result ){
			result = false;
			
			transaction = xmsg.readRequestForTransactionReceipt( rawXmlMsg ) ;
			transaction.setState( Transaction.TS_OPENED ) ;
			
			// 
			instanceID = transaction.getInstanceID() ;
			
			// this is synchronized
			globalReceipts.incGlobalReceiptID(); ;
			transactionID = globalReceipts.getGlobalReceiptID();
			
			transaction.setTransactionID( transactionID ) ;
			 
			// the secret has simply to be reflected, it helps the requesting instance to keep track of a request
			// and to assign the "correct" taskpackage... although there is not exactly a "correct" assignment, 
			// it nevertheless helps to be consistent also under heavy frequencies...
			clientsecret = xmsg.getSpecifiedInfo(rawXmlMsg, "//request/secret", "value");
			
			xreg = messageBoard.retrieveRegistrationObject( instanceID ) ; 
			// XRegistration
				
			if (xreg != null){
				
				// making the global IDs persistent
				msgBoardStorage.saveMsgBoardData() ;
				
				transactionID = transaction.getTransactionID() ;
				transaction.setState( Transaction.TS_ID_ASSIGNED ) ;
				
				
				xmloutmsg = xmsg.createTransactRequestReceipt( xreg, instanceID, transactionID , clientsecret) ;
				
												out.print(3, "returning Transaction Request Receipt, transactionID = " + 
															 transactionID + ", using port " + xreg.getClientListeningPort()+", which is owned by instance id:"+instanceID );
												
				r = wrappedSending( xmsg, xreg, xmloutmsg, "/data", "post",0) ; // 0 -> will use the same value as by "getClientListeningPort()" 
					if (r==0){
						transactions.addItem(transaction);
						transaction.setState(Transaction.TS_ID_CONFIRMED);
					}
					
				
				result = true;
				
			} else// xreg != null ?? == registration object found ?
			{
				// actually, the low-level protocol socket would know about the last connection and 
				// the address, such we could return the notification to re-register.
				// as we do it in case of http-restlet
				
				out.print(2, "No matching registration found for Instance ID "+instanceID+", no further activities.");
				result = false;
			}
		}  
		
		return result;
	}


	
	
	class DeSynchroSend{
		ReceptorLink receptorLink ;
		
		
		public DeSynchroSend(ReceptorLink receptorlink ){
			receptorLink  = receptorlink ;
			isynchedsend(receptorLink);
		}
		public void isynchedsend( ReceptorLink receptorLink ){
			

			
			int port, r;
			String xmlOutMsg;
			Transaction transaction;
			
			
			XMessage xmsg = new XMessage(out) ;
			
			
			port = receptorLink.getReceptorPort() ;
			xmlOutMsg = receptorLink.getXmlStr() ;
			transaction = receptorLink.getTransaction() ;
			
			// if (participantIsAvailable == true)
			{	// we need a confirmation process here ?! 
										out.print(3, "sync'ed sending through port "+port+"...");			
				
				// in case of httpc-rest, this is a within-session reply, hence: no path, no method 
				r = wrappedSending( xmsg, null, xmlOutMsg, "","", port) ;
				
				 	if (r<0){
				 				out.printErr( 2 , "transaction (tid:"+transaction.getTransactionID()+") and its data FAILED to be sent to RECEPTOR, assuming port "+port+" ...    ");
				 	}else{
								out.print(2, "transaction (tid:"+transaction.getTransactionID()+") and its data sent to RECEPTOR, assuming port "+port+" ...    ") ;
				 	}
				// actually: ONLY upon confirmation !!!
										
				
				transaction.setDeliveryPort(port) ;
				
				transaction.setState( Transaction.TS_TASK_DELIVERING) ;
				
				transaction.setTransactErrorState( Transaction.TS_ERR_NO ) ;
				
				transactions.save();
				
										out.print(5, "transaction (tid:"+transaction.getTransactionID()+") saved, index="+transactions.size() );
						
				
				sendDataAcceptConfirmation( xmsg,transaction,1);
				
				
			}
		}
		
	} // inner class DeSynchroSend
	
	
	/** 
	 * that's an interfaced method from Intf "SynchronizedMessageDeliveryIntf"
	 * it contains only 1 method.
	 * 
	 * we directly route the incoming call to an adhoc class for separation of program streams
	 * 
	 */
	public void synchedsend( ReceptorLink receptorLink ){
		
		// DeSynchroSend deSynchroSend = 
		new DeSynchroSend(receptorLink);
		
	}
	
	private boolean sourceVariant_RelayedDataRelayToReceptor( XMessage xmsg, String rawXmlMsg, String[] rawIndicators ){
		
		boolean result=false ;
		
		
		result = xmsg.rawIndicatorsCheck( rawXmlMsg, rawIndicators);
		
		if ( result ){
		
												out.printErr(2,"sourceVariant_RelayedDataRelayToReceptor(), "+rawXmlMsg) ;
									
			/*
				<relay>
					<station name="x"/>
					<transaction id="-1" secret="c0be45fb-9003-4ada-a879-779bd65234a5"/>
					<hopcount value="1"/>
				</relay>
			*/
			rawIndicators = new String[]{"<request ","type=\"","<transactionID","<data","<values>",""} ;
			result = sourceVariant_DataAcceptAndRelayToReceptor( xmsg, rawXmlMsg ,rawIndicators) ;
	
			if (result){
				
			}
		}
		return result;
	}



	/**
	 * the confirmation message returning from SOURCE about receiving results <br/>
	 * SOurce perspective: confirmation of delivery of results to SOURCE, <br/> <br/>
	 * we remove the buffer file, remove transaction from storage, ONLY upon the confirmation,  
	 * that the results indeed arrived at the SOURCE
	 * 
	 * 
	 * @param xmsg
	 * @param rawXmlMsg
	 * @param rawIndicators
	 * @return
	 */
	private boolean sourceVariant_ResultDeliveryConfirmation( XMessage xmsg, String rawXmlMsg, String[] rawIndicators ){ 
		boolean result=false , hb;
		long transactionID, iid ;
		String role, bufferfilename, specialAction;
		Transaction transaction;
				
		/*  quite simple, just this
		 * 
			<messageboard name="spela" role="SOURCE">
			 <transaction>
	   			<transactionid value="23" state="26" />
	   			<confirmation type="results"  secret="abc-123456"  OPTIONAL: action="remove" /> 
	   			<instance id="1867"/>
	   			<role value="SOURCE"/>
			 </transaction>
			</messageboard>
		*/									
		result = xmsg.rawIndicatorsCheck( rawXmlMsg, rawIndicators);
		
		if ( result ){
			result = true;
			
			// variant 3 : confirmation of delivery of results, sent by the SOURCE to the BOARD
			//             such that the BOARD can delete the respective buffers
						
				messageBoard.setDeliveryCompleted(true) ;
				
				// stops the sending process
			 
				transactionID = xmsg.getTransactionID(rawXmlMsg) ;
				iid = xmsg.getSpecifiedValue(rawXmlMsg, "instance","id");
				role = xmsg.getSpecifiedInfo(rawXmlMsg, "role", "value");
	
				specialAction = xmsg.getSpecifiedInfo(rawXmlMsg, "confirmation", "action");
				
				if (specialAction==null){
					specialAction="";
				}
				
										out.print(3, "receiving result delivery confirmation (transaction:"+transactionID+" by instance:"+iid+"), updating notifications...");
										
				Notifications notifications;  					
				
				notifications = messageBoard.getWaitingNotifications();
				notifications.removeNotificationByTransactionID( transactionID ) ;
				msgBoardStorage.saveNotificationsDictionary( notifications ) ;
				
				// int n = notifications.size();
				
				if (specialAction.contains("remov")){
					
					transaction = transactions.getTransactionByID(transactionID) ;
					if (transaction!=null){
						
						
						transaction.setTransactState(Transaction.TS_CLOSED );
						transactions.save() ;
						transactions.removeItem(transaction) ; 
						
						
					}
					out.printErr(2, "result delivery (tid:"+transactionID+") has been confirmed, client (id:"+iid+") requested action = remove -> transaction wil be closed.");
					out.printErr(4, rawXmlMsg);
					return true;
				}
				
												out.print(3, "upon confirmation for delivery of results : removing buffer files...");
												
				bufferfilename = msgBoardStorage.createTransactionDataObjTmpFilename(transactionID, iid );
				hb = msgBoardStorage.removeBufferFile(bufferfilename) ;
												out.print(4, "... removal : "+hb+" - file : "+bufferfilename);
				// D:/dev/java/data/test/mb/transactData/~tdata_tid-537_inid-2528.obj  
				// 
				bufferfilename = msgBoardStorage.createTransactionDataObjTmpFilename(transactionID, 0 );
				bufferfilename = bufferfilename.replace("~tdata", "~reqray");
				hb = msgBoardStorage.removeBufferFile(bufferfilename) ;
												out.print(4, "... removal : "+hb+" - file : "+bufferfilename);
				bufferfilename = bufferfilename.replace("~tdata", "~srcreq");
				hb = msgBoardStorage.removeBufferFile(bufferfilename) ;
												out.print(4, "... removal : "+hb+" - file : "+bufferfilename);
				// ---------------------- next one ...
				
				bufferfilename = msgBoardStorage.createTransactionBufferfileName( iid,  transactionID,  role, "BOARD") ;
				// D:/dev/java/data/test/mb/transferBuffer/board/~rn-537-so.btmp
				
				if (fileutil.fileexists(bufferfilename)==false){
					out.printErr(3, "Cleaning up, file for transaction buffer not found ! ("+bufferfilename+")");
					// D:/dev/java/data/test/mb/transferBuffer/board/~rn-708-so.btmp
					
					bufferfilename = msgBoardStorage.createTransactionBufferfileName( iid,  transactionID,  role, "SOURCE") ;
					if (fileutil.fileexists(bufferfilename)==false){
						out.printErr(3, "Cleaning up (2), file for transaction buffer not found ! ("+bufferfilename+")");
					}	
				}
				 
				hb = msgBoardStorage.removeBufferFile(bufferfilename) ;
												out.print(4, "... removal : "+hb+" - file : "+bufferfilename);
												
				bufferfilename = msgBoardStorage.createTransactionBufferfileName( iid,  transactionID,  "BOARD", "BOARD") ;
				if (fileutil.fileexists(bufferfilename)==false){
					out.printErr(3, "Cleaning up(3), file for transaction buffer not found ! ("+bufferfilename+")");
				}
				msgBoardStorage.removeBufferFile(bufferfilename) ;
				
				 
				transaction = transactions.getTransactionByID(transactionID) ;
				if (transaction!=null){
					transaction.setTransactState(Transaction.TS_RESULTS_RETURNED);
					transactions.save() ;
					transactions.removeItem(transaction) ; // depending on settings, delete or archive
				}
				
				messageBoard.removeNotificationById(transactionID);
				result= true;
		}
		
		return result ;
	}



	private void sendDataAcceptConfirmation( XMessage xmsg, Transaction transaction, int activeRelay){
		
		String xmloutmsg ;
		int r;
		XRegistration xreg ;
		
		long iid, tid;
		String transactionSecret ;
		
		
		transactionSecret = transaction.getClientSecret() ;
		tid = transaction.getTransactionID() ;
		iid = transaction.getInstanceID() ;
		
		BasicMessageParams basics = new BasicMessageParams();
		
		basics.transactionID = tid;
		basics.instanceID = iid;
		basics.privateTransactionIdentifier = transactionSecret;
		basics.roleOfSender = "BOARD" ;

		xmloutmsg = xmsg.createConfirmationAboutDelivery( basics , // tid, iid, transactionSecret, "BOARD", 
														  -1000,"taskdata","c");
		
		if (activeRelay==0){
			xmloutmsg = xmsg.insertRawToXml( originatorID, "originator","id", xmloutmsg, "</messageboard>",1);
		}
		
		xreg = XRegistration.getItemByID( transaction.getInstanceID(), messageBoard.getRegisteredInstances());
		
		if (xreg != null) {
			// on confirmation, we never need a restlet path, since it is within-session !
			r = wrappedSending( xmsg, xreg, xmloutmsg, "", "", 0 ) ;
				if (r<0){
					// message
				}
		}
	}
	/**
	 * 
	 * the DataRelaytoReceptor failed, thus we are here,
	 * 
	 * delay or drop according to settings and/or to message 
	 * 
	 * @param xmsg
	 * @param rawXmlMsg
	 * @param rawIndicators
	 * @return
	 */
	private boolean sourceVariant_DelayedDataRelayToReceptor( XMessage xmsg, String rawXmlMsg, String[] rawIndicators ){
		boolean result=false, hb ;
		long  expiryTime, deliveryTime ;
		
		
		
		result = xmsg.rawIndicatorsCheck( rawXmlMsg, rawIndicators);
		
		if ( result ){
			result = true; 
			
			// long instanceID = xmsg.getinstanceID(rawXmlMsg, "instanceID");
			// long transactionID = xmsg.getTransactionID(rawXmlMsg) ;
			
			// <timedata delivery="1318527853343" expiry="0"/>
			// if expiry is >0 we calculate the longest time period we have to wait for a retry  
			
			deliveryTime = xmsg.getSpecifiedValue(rawXmlMsg, "timedata", "delivery");
			expiryTime = xmsg.getSpecifiedValue(rawXmlMsg, "timedata", "expiry"); // expiry is a relative value
			
			hb = ( (System.currentTimeMillis() - deliveryTime)> expiryTime) || (expiryTime<=0) || (deliveryTime<=0);
			
			if (hb){
				messageBoard.handlingBlockedTransactions(rawXmlMsg);
			}else{
				// start a thread which waits until time is expired, then
				// if the item is still on the waiting list, call "handlingBlockedTransactions()"
				// == filling a list, which is checked upon a new registration
				
				// so far, we break...
				messageBoard.handlingBlockedTransactions(rawXmlMsg);
			}
			// -------------------
		}
		
		return result ;
	}

	
	private int returnErrorMessageUponRequest(  XMessage xmsg, XRegistration xreg, 
												BasicMessageParams basics, // long transactionID, long instanceID, String role, String secret, 
												int stateValue, int errorCode,
												String str){
		
				ErrMessageParams errcomps = new ErrMessageParams() ;
				errcomps.stateValue = stateValue;
				errcomps.errorCode = errorCode;
				errcomps.domainStr ="";
				errcomps.attrValueStr = "";
				
		return returnErrorMessageUponRequest( xmsg, xreg, basics, errcomps, str);
	}
	
	private int returnErrorMessageUponRequest(  XMessage xmsg, XRegistration xreg, 
												BasicMessageParams basics, // long transactionID, long instanceID, String role, String secret, 
												ErrMessageParams errcomps, 
												// int stateValue, int errorCode,String domainStr, String attrValueStr,
												String str){
		
		String xmloutmsg, dataobjStr = "";
		int r=-1; 
		StringedObjects stringedObj = new StringedObjects();
		 
		
		
		dataobjStr = stringedObj.encode(str) ;
		// this needs to be an encoded object as it occurs in normal messages
		xmloutmsg = xmsg.createReturnOfDataUponNotification( basics, //  basics.transactionID, basics.instanceID,  basics.roleOfSender, basics.privateTransactionIdentifier,
															 errcomps.stateValue , errcomps.errorCode,
															 dataobjStr);
		
		xmloutmsg = xmloutmsg.replace("<result ", "<result format=\"text\" ") ;

		
		
				if (errcomps.domainStr.length()>0){
					
					String insertion = "<"+errcomps.domainStr+" value=\""+errcomps.attrValueStr+"\" />" ;
					
					xmloutmsg = xmloutmsg.replace("<result ", insertion+"\r\n<result ");
				}
				
				out.print(4,"error message sent to participant is :\r\n"+ xmloutmsg);
				// instead of plain results as it would have been indicated by full tag "<result>", we return the error code as attributes of this tag
	    r = wrappedSending( xmsg, xreg, xmloutmsg, "", "",0) ;
	    
	    return r;
	}
	
	
	private int deliveryIsNotPossible( XMessage xmsg, XRegistration xreg, 
										   BasicMessageParams basics, Transaction transaction, String bufferfilename ){
	    int result = -1 ;
		boolean  hb;
		String str, errstr,  infoValueStr;
		
		int sv,r;
		
		try{
			
			if (fileutil.fileexists(bufferfilename) ){
				return 0;
			}
			

			out.print(3,"checking buffer file : "+bufferfilename+" , which ...");
			
			{
			out.print(3,"   ... does not exist ...");

			// this is just a normal response if there is no result
			// yet, if the SOURCE has delivered a transaction it may be waiting, while the transaction has not
			// been delivered to, or returned by a RECEPTOR, so we have to check the state before indicating an error !!

			str=""; sv = 0;
			hb = false;

			ErrMessageParams errcomps = new ErrMessageParams() ;
			
			sv = transaction.getTransactState() ;
			str = Transaction.decodeTransactionCode(sv) ;

			// this also checks the expiry date condition
			hb = transaction.isAlive(1); // 1 == relaxed, do not rate DENIED as an error state!

			if (hb == false){
				errstr = "Requested transaction id="+basics.transactionID+" for instance of id="+basics.instanceID+" is not available any more." ;
			}

			errstr = "\nAttempt to serve results about transaction id="+basics.transactionID+" encountered a storage problem: buffer file does not exist ! \n"+
			"Reason: "+str+"(code:"+sv+")";
			
			if (sv == Transaction.TS_RESULTS_BUFFERED){
				
				infoValueStr="";
				
				// state says that T has been buffered, but there is no file => serious error condition
				
						errcomps.stateValue = -Transaction.TS_RESULTS_BUFFERED;
						errcomps.errorCode = Transaction.TS_ERR_TRANSINVALID;
						errcomps.domainStr = "age";
						errcomps.attrValueStr = infoValueStr;
				
				r = returnErrorMessageUponRequest( xmsg, xreg,basics, errcomps,str);
													// -Transaction.TS_RESULTS_BUFFERED, Transaction.TS_ERR_TRANSINVALID,"age", infoValueStr, str) ;

				return sv;


			}

			if (sv == Transaction.TS_TASK_ACCEPTED){
				// transferBuffer/board/~rn-771-bo.btmp does not exist ...
				// may be, that it has not yet been calculated
				// ok, but the file     ~rn-771-so.btmp SHOULD exist !!
				// if not we return a message
				str = msgBoardStorage.createTransactionBufferfileName( transaction, "SOURCE" );
				
				if (fileutil.fileexists(str)==false){
					
							errcomps.stateValue = -Transaction.TS_TASK_ACCEPTED;
							errcomps.errorCode = Transaction.TS_ERR_TIMEDOUT;
							errcomps.domainStr = "";
							errcomps.attrValueStr = "";
					
					r = returnErrorMessageUponRequest( xmsg, xreg,basics, errcomps,str);
						if (r<0){
							
						}
													   // -Transaction.TS_TASK_ACCEPTED, Transaction.TS_ERR_TIMEDOUT,"", "", str) ;
				}
				return -2;
			}
			
	
						out.print(3 ,errstr+" -> "+bufferfilename );
						
			if (sv== Transaction.TS_TASK_DELIVERING){
			// there should be an immediate confirmation...
			// check when it has been attempted to deliver... and if old, return a cancel message to the source

				if (transaction.isOld(15,"min")){

					out.printErr(3, "transaction id="+transaction.getTransactionID()+" seems to be lost... it will be canceled.");
					// remove transaction from mb's memory, delete any kind of file about it, send cancel notification
					transactions.removeItem(transaction) ;

					// this messages has to match "replyVariant_HandlingErrorMsgOnResultsRequest"
					// rawIndicators = new String[]{"<return ", "type=\"results\"", "<transactionID", "<result state=\"error"} ;

					// ??? where does this come from ??? "<terminated, exit value: 1>C:\Programs\Java\jre6\bin\javaw.exe (06.11.2011 20:07:38)	

						out.print(3, "returning cancel message for transaction id="+basics.transactionID+"") ;
						
			        str = "internal state was: "+Transaction.decodeTransactionCode(Transaction.TS_TASK_DELIVERING) ;
 
			        r = returnErrorMessageUponRequest( xmsg, xreg,basics, // transactionID, instanceID, role,secret,
											   	       Transaction.TS_TASK_NOTRANSFER , Transaction.TS_ERR_TIMEDOUT, str) ;
			        							// TS_TASK_NOTRANSFER = -TS_TASK_DELIVERING !
			        return -4;

			}else {return sv;}
			}

			if (sv== Transaction.TS_TASK_DIGESTING){
				// if digesting but delivery time is > 20 days, sth went wrong in calculations
				// -> send a cancel message to source, delete file if existing 
				str = "internal state was: "+Transaction.decodeTransactionCode(Transaction.TS_TASK_DIGESTING) ;

				infoValueStr = "-1"; 
				if (transaction!=null){
					infoValueStr = ""+ transaction.getAge(2);
				}
				
							errcomps.stateValue = Transaction.TS_TASK_DIGESTING;
							errcomps.domainStr = "age";
							errcomps.attrValueStr =infoValueStr;
							
				// if it is "very" old , ...several days ??? 
				if (transaction.isOld( transaction.ageThresholdForDigestingTasks, "days")){
					
							errcomps.errorCode = Transaction.TS_ERR_TIMEDOUT;
					r = returnErrorMessageUponRequest( xmsg, xreg,basics, errcomps,str); //  Transaction.TS_TASK_DIGESTING, Transaction.TS_ERR_TIMEDOUT,"age", infoValueStr, str) ;
					return sv;
				}else {
							errcomps.errorCode = 0;
					r = returnErrorMessageUponRequest( xmsg, xreg,basics, errcomps, str); //  Transaction.TS_TASK_DIGESTING ,0, "age", infoValueStr, str) ;
					return -4;
				}
			}
			if (hb){
			// is there a conflict: requested, indicated as buffered, but no file around?

				str = "internal state was: "+Transaction.decodeTransactionCode(Transaction.TS_RESULTS_BUFFERED) ;

					if (sv <= Transaction.TS_TASK_DELIVERED) {
						// here we have to care for large files and upload times ...
						if (transaction.isOld(15, "min")) {
							r = returnErrorMessageUponRequest(xmsg, xreg, basics, Transaction.TS_RESULTS_BUFFERED,Transaction.TS_ERR_TIMEDOUT, str);
						} else {
							return sv;
						}
					}

				}
				if (hb == false) {
					out.printErr( 2, "Transaction id=" + basics.transactionID + " will be removed from the MessageBoard, notification has been sent!");
					
					transactions.removeItemByID(basics.transactionID);
					sendErrorMessageToClient(xmsg, xreg, basics, Transaction.TS_TASK_CANCELED, errstr, Transaction.TS_ERR_BUFFNOTFOUND);
				}
				return -4;
			} // fileexists(bufferfilename) ?
 
		}catch(Exception e){
			
		}
		
		return result ;
	}
	
	
	private void sendErrorMessageToClient( XMessage xmsg, XRegistration xreg,
										   BasicMessageParams basics, // long transactionID, long instanceID, String role, String secret ,
										   int transactionStateValue, String errstr, int errcode ) {
		// basics.transactionID,basics.instanceID, basics.roleOfSender, basics.privateTransactionIdentifier,
		String xmloutmsg, xmlRestPrefix;
		Transaction transaction;
		int  r;
		
		transaction = new Transaction();
		
		transaction.setDataObject(errstr) ;
		transaction.setErrorState( errcode );
		transaction.setClientSecret(basics.privateTransactionIdentifier) ;
		transaction.setRoleOfInitializer(basics.roleOfSender) ;
		transaction.setTransactionID(basics.transactionID) ; 
		transaction.setInstanceID(basics.instanceID) ;
		transaction.setTransactState( transactionStateValue );
		transaction.setResultObject( errstr );
		
		errstr = errstr.replace("\n\r", "<br/>");
		errstr = errstr.replace("\n", "<br/>");
		
		xmloutmsg = xmsg.createReturnOfDataUponNotification( transaction, basics.roleOfSender, basics.privateTransactionIdentifier);

		xmloutmsg = xmloutmsg.replace("<result>", "<result state=\"error\" value=\""+errcode+"\">") ;
		
		xmloutmsg = xmloutmsg.replace("<result ", "<result format=\"text\" ") ;
		// xmloutmsg = xmsg.insertRawToXml( originatorID, "originator","id", xmloutmsg, "</messageboard>",1);
												if (errcode!=0){
													out.printErr(3, "\nreturning error message to participant (error code = "+errcode+" -> "+Transaction.decodeTransactionCode(errcode)+")") ;
												}
		if (mbf.getFactoryProperties().getProtocolId()<= MessageBoardFactoryProperties.protocolFTP){
			//  originator will be added in wrapped sending, if necessary , prolog
			// in case of http, it will be an in-session response, no path needed thus.   
		}
		if (xreg != null) {
			 
			r = wrappedSending( xmsg, xreg, xmloutmsg, "", "",0) ;
			 
				if (r<0){
						out.printErr(3, "error messge FAILED to be sent\n"+xmloutmsg+"----------------------------------------\n");
				}else{
						out.print(4, "error messge sent!  \n"+xmloutmsg+"----------------------------------------\n");
				}
		}
		
		// remove transaction from storage
		
	}
	
	
	
	private boolean sourceVariant_ResultsDeliveryDenied( XMessage xmsg, String rawXmlMsg, String[] rawIndicators ) {
		boolean result=false ;
		long instanceID, transactionID;
		
		
		
		result = xmsg.rawIndicatorsCheck( rawXmlMsg, rawIndicators);
	
		if ( result ){
			
			instanceID = xmsg.getinstanceID(rawXmlMsg, "instanceID");
			transactionID = xmsg.getTransactionID(rawXmlMsg) ;
			
			out.print(3,"Participant "+instanceID+" confirmed notification about transaction "+transactionID+", yet signalled to drop the results.") ;
				
			// messageBoard
		}
	
		return result ;
	}

	private boolean sourceVariant_TransactionHandlingExplicites( XMessage xmsg, String rawXmlMsg, String[] rawIndicators ){
		/*
			<messageboard name="spela" role="SOURCE">
    			<transaction>
       			<transactionID value="548"/>
       			<issuer instanceID="2528" secret=""/>
       			<notification type="results"/>
       			<action value="drop"/>
    			</transaction>
 			</messageboard>
		*/
		boolean result=false ;
		String actionValue;
		
		@SuppressWarnings("unused")
		long iid,tid, notificationID;
		Transaction transaction;
		
		
		result = xmsg.rawIndicatorsCheck( rawXmlMsg, rawIndicators);
		
		if ( result ){
		
			iid = xmsg.getinstanceIDfromIssuer(rawXmlMsg) ;
			tid = xmsg.getTransactionID(rawXmlMsg) ;
			
			notificationID = xmsg.getSpecifiedValue(rawXmlMsg, "notification", "id") ; 
			actionValue = xmsg.getSpecifiedInfo(rawXmlMsg, "action", "value") ;
			
												out.print(3, "explicit action ("+actionValue+") on transaction id="+tid);
			
			if (actionValue.contentEquals("drop")){
				transaction = transactions.getTransactionByID( tid) ;
				messageBoard.removeNotificationById( tid); 
				
				if (transaction!=null){
					transactions.removeItem(transaction) ;
					// see: wxyz  
				}
			}
			
		}
		
		return result ;
	}

	private boolean sourceControl_CancelReceptorTaskbyTransactionID( XMessage xmsg, String rawXmlMsg, String[] rawIndicators ){ 
		/*
		 
		<messageboard name="spela" role="SOURCE">
			<transaction>
				<control secret="a1bcd-123"/>
	  			<transaction id="440" />
	  			<instance id="1867"/>
	  			<task param="" type="cancel"/>
	  			
			</transaction>	 
		</messageboard>
	
	
		*/
		boolean result=false , stateB = false;
		long tid, iid ;
		int deliveryPortOfTransaction, terrstate,r, tstate;
		XRegistration xreg;
		String  privateSecret, str,  xmlout, taskParam;
		Transaction transaction;
		SenderWrap sender ;
		
		
		result = xmsg.rawIndicatorsCheck( rawXmlMsg, rawIndicators);
		
		if ( result ){
			result = true;
			
			BasicMessageParams basics = new BasicMessageParams();
			
			iid = xmsg.getSpecifiedValue(rawXmlMsg, "instance","id"); //getinstanceID(rawXmlMsg, "instance");
			tid = xmsg.getTransactionID(rawXmlMsg) ;
			
			privateSecret = xmsg.getSpecifiedInfo(rawXmlMsg, "control", "secret") ;
			 
			str = xmsg.getSpecifiedInfo(rawXmlMsg, "task", "type") ;
			
			xreg = messageBoard.retrieveRegistrationObject( iid ) ; 
			
			// ................
			
			if ((str.contentEquals("cancel")) && (tid==-9) && (iid>0)){
				
				
				privateSecret = xmsg.getSpecifiedInfo(rawXmlMsg, "instance", "name") ;
				
				if (xreg.getNameOfApplicant().contentEquals(privateSecret)==false){
					return result;
				}
				
				taskParam = xmsg.getSpecifiedInfo(rawXmlMsg, "task", "param") ;
					
				messageBoard.handlingInternalControlTask( iid, originatorID, str, taskParam, rawXmlMsg ) ;
				// this will create an instance of the ControltaskHandler 
				
				/* confirmation will be returned in the ControlTaskHandler
				  
				basics.transactionID = tid;
				basics.instanceID = iid;
				basics.privateTransactionIdentifier = privateSecret;
				basics.roleOfSender = "BOARD" ;
				
				// send confirmation back to the source
				xmlout = xmsg.createConfirmationAboutDelivery( basics, // tid, iid, privateSecret, "BOARD", 
															   -1000,"task::cancel-all","c");
				 
				// we could put the request for explicit confirmation into the message;
				// but then we should not return it here, but in the handler (class ControlTaskHandler{})
				
				r = wrappedSending( xmsg, xreg, xmlout , "", "",0) ; // rawXmlMsg
				 	if (r<0){
				 		out.print(2, "returning response to task message failed.");
				 		out.print(2, ""+xmlout);
				 	}
				*/
			}
			
			// ................
			
			if ((str.contentEquals("cancel")) && (tid>0)){
				
				// String paramstr = xmsg.getSpecifiedInfo(rawXmlMsg, "task", "param") ;
				
				transaction = transactions.getTransactionByID(tid) ; // AAAAAAAAAAAAAAAAA
				// create relay to Receptor -> find listening port for respective receptor
				
				if (transaction!=null){
					
												out.print(5, "CancelMsg: transaction found, id="+tid);
					// -1?
					deliveryPortOfTransaction = transaction.getDeliveryPort() ;
					tstate = transaction.getTransactState() ; // Transaction.TS_TASK_DELIVERED , Transaction.TS_TASK_DENIED) ;
					terrstate = transaction.getTransactErrorState() ; // Transaction.TS_ERR_NOMATCH 
					
					stateB = (tstate!= Transaction.TS_TASK_DENIED) &&  (tstate< Transaction.TS_RESULTS_RETURNED) && (tstate > Transaction.TS_ID_CONFIRMED) ; 
					
					if ((deliveryPortOfTransaction>0) && (stateB ) && (terrstate==0)){
						// send it to the receptor
						
						
						sender = new SenderWrap(messageBoard) ;
						r = sender.sendingMessage(rawXmlMsg, deliveryPortOfTransaction) ;
							if (r<0){
								out.printErr(3, "sendingMessage() failed in sourceControl_CancelReceptorTaskbyTransactionID(), code="+r);
							}
						sender=null;
						// "remove" the transaction from the board's list : it won't find the way back to the Source 
						// == set it to canceled
						transaction.setTransactErrorState( Transaction.TS_ERR_STOPPED) ;
						transaction.setState(Transaction.TS_TASK_CANCELED) ;
						transactions.save() ;
												out.printErr(4, "CancelMsg: info (tid:"+tid+") & state ok, relaying "+
																"(port:"+deliveryPortOfTransaction+") and confirming "+
																"(port:"+xreg.getClientListeningPort()+") this message ... ");
												 
						
						
						
						basics.transactionID = tid;
						basics.instanceID = iid;
						basics.privateTransactionIdentifier = privateSecret;
						basics.roleOfSender = "BOARD" ;
						
						// send confirmation back to the source
						xmlout = xmsg.createConfirmationAboutDelivery( basics, // tid, iid, privateSecret, "BOARD", 
																	   -1000,"task::cancel","c");
						// ??
						r = wrappedSending( xmsg, xreg, xmlout , "", "",0) ; // rawXmlMsg
						 	if (r<0){
						 		
						 	}
					} // port and state ok?
					else{
						out.print(2, "CancelMsg: transaction found, but conditions not met.");
					}
				} // transaction is known ?
				else{
					out.print(2, "CancelMsg: message decoded, but desired transaction not found.");
				}
			} // is it the cancel command
			
			
			
			result = true;
		}
		
		return result ;
	}



	private void denyTaskAcceptance( XMessage xmsg, String rawXmlMsg, long iid, long tid, int reasonCode ) {
	
		String xmlstr ;
		XRegistration xreg ;
		String secret="";
		int r;
		
		
		BasicMessageParams basics = new BasicMessageParams();
		
		
		xreg = messageBoard.retrieveRegistrationObject( iid ) ; 
		 
			
		if (xreg != null){
			
			secret = xmsg.getSpecifiedInfo(rawXmlMsg, "request", "secret")  ;
			
			basics.privateTransactionIdentifier = secret;
			basics.transactionID = tid;
			basics.instanceID = iid;
			basics.instanceName = xreg.getNameOfApplicant() ;
			basics.roleOfSender = "BOARD" ;
			
			xmlstr = xmsg.createRegistrationDenialReply( basics, reasonCode, "reason description");
			
			
			r = wrappedSending( xmsg, xreg, xmlstr, "", "",0) ;
				if (r<0){
					out.printErr(3, "sendingMessage() failed in denyTaskAcceptance(), code="+r);
				}
			 
		}
		 
	}
 
	public void assimilateReloadedTransactions( Transactions transactions ){
		String rawXmlMsg="";
		int xp;
		long iid, tid;
		String filename, doctype;
		
		long[] tids;
		int[] openStates ;

		Transaction transaction=null;
		AssimilateContext ac ;
		
		
		openStates = new int[]{ Transaction.TS_TASK_CONFIRMED, Transaction.TS_OPENED,
				  				Transaction.TS_TASK_DIGESTING, Transaction.TS_TASK_ACCEPTED };
		
		Arrays.sort(openStates) ;
		tids = transactions.getOpenTransactions( openStates ) ;
		
		for (int t=0;t<tids.length;t++){
		
			tid = tids[t] ;
			transaction = transactions.getTransactionByID(tid) ;
			
			// reload the xml file from buffer
			iid = transaction.getInstanceID() ;
			tid = transaction.getTransactionID() ;
			doctype = transaction.getContentType() ;
			
			// find the file & load it
			filename = msgBoardStorage.createTransactionDataObjTmpFilename( tid, iid );
			filename = filename.replace("/~tdata_", "/~srcreq_") ;
			
			try{
				Object obj = msgBoardStorage.readTransactionDataObj(filename);
				rawXmlMsg = (String)obj;
				
			}catch(Exception e){ rawXmlMsg =""; }
			
			
			// check it briefly
			xp = rawXmlMsg.indexOf("<context") ; 

			//
			if ((xp>0) && (tid>0) && (doctype.length()>0) && (rawXmlMsg.length()>0) && (transaction != null)){
				
				ac = (new AssimilateContext( rawXmlMsg, transaction)).get(1);
			} // is it a xml with context ?
		
		} // t->
		
	}
	
	class AssimilateContext implements Runnable{
		
		SourceMessageInterpreter interpreterParent ;
		Transaction transaction;
		String rawXmlMsg;
		
		ActiveContextHeaderDescriptions chds; 
		
		boolean finished=false;
		boolean isRunning;

		Thread smiAcThrd;
		
		
		
		public AssimilateContext(  String xmlMsg, Transaction transact){
			
			transaction = transact;
			rawXmlMsg = xmlMsg;
			interpreterParent = smi;
		
			smiAcThrd = new Thread(this ,"smiAcThrd");
			smiAcThrd.start() ;
		}

		public AssimilateContext get( int wait ){
			
			while (isRunning==false){
				Thread.yield() ;
			}
			while ((wait>=1) && (isRunning)){
				delay(1);
			}
			return this;
		}
		
		private void handlingContextInfo(){
			ContextHeaderDescription chd; 
			int dataType, ix ;
			long tid , iid;
			
			
			try{
				// the MessageBoard knows about a list of all issued contexts: "ActiveContextHeaderDescriptions{}"
				// this lives a "few" seconds, and knows to whom of the subscribers it already has been sent.
				// this allows for asynchronous "pull" mechanisms still to catch those ContextInfo, even
				// if they are not registered while the ContextInfo has been published on the board.
				
				// all registered instances that have published a future will get an entry directly into
				// a collection, which is part of XRegistration
				
				chd = new ContextHeaderDescription( smi.messageBoard );
				chds = smi.messageBoard.getActiveContextHeaderDescriptions() ;
				
				/* context info is quite simple, either it is 
					- a whole-sale format like text or image,
					- an item set, or a 
					- feature vector
					
					note that full contexts may be contained as encoded objects !! 
				*/ 
				Context _context = cxmsg.readContextInfoFromXml(rawXmlMsg) ; // ???? context, full text/image ??? 

				
				if (_context==null){
					return ;
				}
				
				tid = transaction.getTransactionID() ;
				iid =  transaction.getInstanceID(); 
				
				ix = chds.getItemIndexByTransactionID( tid );
				if (ix>=0){
					
					return;
				}
				
				chd.setInstanceID( iid );
				chd.setTransactionID( tid ) ;

				dataType = _context.getDataType();
				chd.setCDataType( dataType );
				
				chd.setDisclosureAllowData( _context.getDisclosureAllowData() );
				chd.setDisclosureAllowName(_context.getDisclosureAllowName() );
				
				chd.setNameOfIssuer( _context.getNameOfIssuer() ) ;
				chd.setRoleOfIssuer( _context.getRoleOfIssuer() );
				
				if (_context.getContextStyle() == ContextInfra._CSTYL_JUSTINFO){
					
				}
				if ( dataType == ContextInfra._DTYP_ITEMS){
					chd.setItemSet( _context.getItemSet()) ;
					chd.setLabel( _context.getLabel() ) ;
				}
				if ( dataType == ContextInfra._DTYP_FVECTOR){
					chd.setItemSet( _context.getFeatureSet() ) ;
					chd.setDataItems( _context.getFeatureValues() ) ;
				}
				if ( dataType == ContextInfra._DTYP_FULLTEXT){
					// ...
					chd.setFulltext( _context.getFullText() ) ;
				}
				if ( dataType == ContextInfra._DTYP_BINIMG){
					// ...
				}
				
				
				ix = chds.getItemIndexByTransactionID(tid);
				// addItem() is synch'ed and (should...) avoids double listings
				// chds is a handle to the collection of all context header descriptions...
				// note that "chds" derive ONLY from the context-section of xml messages 
				if (ix<0){
					chds.addItem(chd) ;
				}
				
			}catch(Exception e){
				e.printStackTrace();
			} finally{
				finished=true;
			}
		}


		@Override
		public void run() {
			
			isRunning = true;
			
			handlingContextInfo() ;
			
			isRunning = false;
		}
		 
		
	}
	
	 

}
